#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <string>
#include <list>
#include <cstdio>
#include <exception>
#include <pthread.h>
#include <stdbool.h>
#include "locker.h"
#include "inotify.h"
#include "log.h"

using namespace std;

template< typename T >
class threadpool {
public:
    threadpool(int thread_number = 8, int max_requests = 10000, Inotify *inot = NULL);
    ~threadpool();
    bool append(T dir);

private:
    static void* worker(void* arg);
    void run();

private:
    int m_thread_number;
    int m_max_requests;
    Inotify *m_inot;    
    pthread_t* m_threads;
    std::list< T > m_workqueue;
    locker m_queuelocker;
    sem m_queuestat;
    bool m_stop;
};

template< typename T >
threadpool< T >::threadpool(int thread_number, int max_requests, Inotify *inot) :
m_thread_number(thread_number), m_max_requests(max_requests), m_inot(inot), m_threads(NULL), m_stop(false) {
    if ((thread_number <= 0) || (max_requests <= 0)) {
        throw std::exception();
    }

    m_threads = new pthread_t[ m_thread_number ];
    if (!m_threads) {
        throw std::exception();
    }

    for (int i = 0; i < thread_number; ++i) {
        printf("create the %dth thread\n", i);
        if (pthread_create(m_threads + i, NULL, worker, this) != 0) {
            delete [] m_threads;
            throw std::exception();
        }
        if (pthread_detach(m_threads[i])) {
            delete [] m_threads;
            throw std::exception();
        }
    }
}

template< typename T >
threadpool< T >::~threadpool() {
    delete [] m_threads;
    m_stop = true;
}

template< typename T >
bool threadpool< T >::append(T dir) {
    m_queuelocker.lock();    
    if (m_workqueue.size() > m_max_requests) {
        log_info("work queue size is overfllow [%d]", m_workqueue.size());
        m_queuelocker.unlock();
        return false;
    }    
    m_workqueue.push_back(dir);
    m_queuelocker.unlock();
    m_queuestat.post();
    return true;
}

template< typename T >
void* threadpool< T >::worker(void* arg) {
    threadpool* pool = (threadpool*) arg;
    pool->run();
    return pool;
}

template< typename T >
void threadpool< T >::run() {
    //int flag = rand()%16 + 1;
    while (!m_stop) {        
        m_queuestat.wait();
        m_queuelocker.lock();
        if (m_workqueue.empty()) {
            m_queuelocker.unlock();
            continue;
        }             
        T dir = m_workqueue.front();
        //fprintf(stdout, "pool[%d] front: %s\n", flag, dir.c_str());        
        m_workqueue.pop_front();
        m_queuelocker.unlock();
       
        if (dir.size() == 0) {
            continue;
        }        
        m_inot->process(dir);       
        //fprintf(stdout, "pool[%d] finish\n", flag); 
    }
}

#endif
